//
//  JWSquare.m
//  KotH
//
//  Created by James Weatherley on 02/08/2008.
//  Copyright 2008 James Weatherley. All rights reserved.
//

#import "../koth.h"
#import "../wolfiphone.h"
#import "../geometry/geometry.h"

//#define SAME_CLOCKNESS 1
//#define DIFF_CLOCKNESS 0

@implementation JWSquare

//BOOL checkIntersectQuad(vec3_t q0, vec3_t q1, vec3_t q2, vec3_t q3,
//						vec3_t intersect,
//						vec3_t normal);

//BOOL hitBoundingBox(vec3_t boxMin, vec3_t boxMax, vec3_t point, vec3_t direction);


@synthesize x;
@synthesize z;
@synthesize height;
@synthesize number;
@synthesize boxes;
@synthesize topBox;
@synthesize flat;
@synthesize tree;
@synthesize robot;
@synthesize player;
@synthesize sentinel;
@synthesize selected;
@synthesize endOfLevel;

-(id)initWithPositionX:(int)x_ z:(int)z_ height:(double)height_ number:(NSInteger)number_;
{
	self = [super init];

	x = x_;
	z = z_;
	height = height_;
	number = number_;
	
	flat = YES;
	tree = NO;
	selected = NO;
	player = NO;
	endOfLevel = NO;
	
	boxes = [[NSMutableArray alloc] init];
	
	return self;
}

-(void)dealloc
{
	[super dealloc];
	[boxes release];
}

-(double)incrementHeight
{
	return ++height;
}

-(BOOL)canMoveTo
{	
	BOOL legal = NO;
	
	if(flat && !tree) {
		if(!player && !sentinel && ![robot square]) {
			legal = YES;
		}
	}
	return legal;
}

#pragma mark Selection
-(void)setSelected:(BOOL)isSelected
{
	if(selected != isSelected) {
		selected = isSelected;
		if(tree) {
			tree.selected = isSelected;
			JWTreeManager* manager = (JWTreeManager*)[[JWManagers sharedManager] managerOfClass:[JWTreeManager class]];
			[manager updateVertexArrays];
		} else {
			if([boxes count]) {
				for(JWBox* box in boxes) {
					box.selected = isSelected;
				}
			}
			if(robot) {
				robot.selected = isSelected;
			}
		}
		JWLandscapeManager* manager = (JWLandscapeManager*)[[JWManagers sharedManager] managerOfClass:[JWLandscapeManager class]];
		[manager updateVertexArrays];
	}
}

-(BOOL)selected
{
	return selected;
}

#pragma mark Box Methods
-(NSInteger)boxCount
{
	return [boxes count];
}

-(void)addBox:(JWBox*)box
{
	topBox = box;
	[boxes addObject:box];
}

-(void)removeBox:(JWBox*)box
{
	[boxes removeObject:box];
	NSUInteger size = [boxes count];
	
	if(size) {
		topBox = [boxes objectAtIndex:size - 1];
	} else {
		topBox = 0;
	}
}

-(void)updateTopBox
{
	if([boxes count]) {
		topBox = [boxes objectAtIndex:[boxes count] - 1];
	} else {
		topBox = nil;
	}
}

-(void)setVerticesA:(vec3_t)a B:(vec3_t)b C:(vec3_t)c D:(vec3_t)d
{
	vectorCopy(a, vertexA);
	vectorCopy(b, vertexB);
	vectorCopy(c, vertexC);
	vectorCopy(d, vertexD);

	vectorCopy(vertexA, verticesABCD[0]);
	vectorCopy(vertexB, verticesABCD[1]);
	vectorCopy(vertexC, verticesABCD[2]);
	vectorCopy(vertexD, verticesABCD[3]);
	
	calculateNormal(a, b, c, normal);
}

-(void)getVerticesA:(vec3_t)a B:(vec3_t)b C:(vec3_t)c D:(vec3_t)d
{
	vectorCopy(vertexA, a);
	vectorCopy(vertexB, b);
	vectorCopy(vertexC, c);
	vectorCopy(vertexD, d);
}

-(void)setColour:(GLfloat*)theColour
{
	for(int i = 0; i < 3; ++i) {
		colour[i] = theColour[i];
	}
}

#pragma mark Drawing 
-(void)drawSelf
{
	vec3_t squareColour;
	
	// Set the square's colour.
	int index = (z & 1) ? (x & 1) : !(x & 1);
	if(flat) {
		if(selected) {
			vectorCopy(selectedColour, squareColour);
		} else if(tree) {
			vectorCopy(underTreeColour, squareColour);
		} else {
			vectorCopy(flatColours[index], squareColour);
		}
	} else {
		vectorCopy(cliffColours[index], squareColour);
	}
	
	// Draw it.
	//pfglBegin(GL_QUADS);
	pfglColor4f(squareColour[0], squareColour[1], squareColour[2], 1.0f);
	pfglNormal3f(normal[0], normal[1], normal[2]);
	pfglVertex3f(vertexA[0], vertexA[1], vertexA[2]);
	pfglVertex3f(vertexB[0], vertexB[1], vertexB[2]);
	pfglVertex3f(vertexC[0], vertexC[1], vertexC[2]);
	pfglVertex3f(vertexD[0], vertexD[1], vertexD[2]);
	//pfglEnd();

	// Reset normal vector.
	//qglNormal3f(0, 1, 0);
}


-(NSString*)description
{
	NSString* str = [NSString stringWithFormat:@"x: %d\nz: %d\nh: %lf\n n:%d\n", x, z, height, number];
	return str;
}


#pragma mark Picking
-(BOOL)intersectWithRayFromPoint:(vec3_t)point direction:(vec3_t)vec
{
	BOOL inSquare = NO;
	vec3_t intersection;
	if(intersectPlane(vertexA, normal, point, vec, intersection)) {
		inSquare = intersectPolygon(verticesABCD, 4, intersection, normal);
	}
	
	return inSquare;
}

-(BOOL)intersectBoundingBoxWithRayFromPoint:(vec3_t)point direction:(vec3_t)vec boxesOnly:(BOOL)boxesOnly
{	
	assert(flat);
	BOOL inBoundingBox = NO;
	NSInteger boundingBoxHeight = 0;
	
	if(self.tree) {
		inBoundingBox = [tree intersectWithRayFrom:point direction:vec];
	} 
	
	if(!inBoundingBox) {
		boundingBoxHeight += [boxes count];
	
		if(!boxesOnly) {
			if(self.robot) {
				boundingBoxHeight += 1;
			} else if(self.sentinel) {
				boundingBoxHeight += 2;
			}
		}
		
		vec3_t boundingBoxMin = {
			fmin(vertexA[0], fmin(vertexB[0], fmin(vertexC[0], vertexD[0]))), 
			height,
			fmin(vertexA[2], fmin(vertexB[2], fmin(vertexC[2], vertexD[2])))
		};
		
		vec3_t boundingBoxMax = {
			fmax(vertexA[0], fmax(vertexB[0], fmax(vertexC[0], vertexD[0]))), 
			height + boundingBoxHeight,
			fmax(vertexA[2], fmax(vertexB[2], fmax(vertexC[2], vertexD[2])))
		};
		
		inBoundingBox = intersectBox(boundingBoxMin, boundingBoxMax, point, vec);
	}
	
	return inBoundingBox;
}

#pragma mark Sorting
-(NSComparisonResult)sortByHeight:(JWSquare*)s
{
	if(s.height == height) {
		return NSOrderedSame;
	} else if(s.height < height) {
		return NSOrderedDescending;
	} else {
		return NSOrderedAscending;
	}
}

@end
